import os

os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'  # 去警告
import tensorflow as tf


# 准备真实数据：
# x：特征值，形状：（100,1）
# y_true：目标值 （100,1）
# y_true = 0.8x + 0.7 ，100个样本
# 假设满足： y =kx + b
#
# 分析：
#   由：[100,1] = [100,1] * [1,1]
#   得：y_predict = x * weights(1, 1) + bias(1,1)
# 1.构造模型
#   即：y_predict = tf.matul(x, weights) + bias(1,1)
# 2.构造损失函数
#      tf.reduce_mean( tf.square(y_predict - y_ture) )
# 3.优化损失（梯度下降优化器）
#      tf.train.GrandientDescentOptimizer(learning_rate=0.01)

def linear_refression():
    """
    自实现线性回归
    :return
    """
    # 1.准备数据
    X = tf.random.normal(shape=[100, 1])  # 特征值 100行1列
    y_true = tf.matmul(X, [[0.8]]) + 0.7  # 真实值 y_true = 0.8x + 0.7
    # 2.定义变量
    weights = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]))  # 权重
    bias = tf.Variable(initial_value=tf.random.normal(shape=[1, 1]))  # 偏置
    variables = [weights, bias]
    # 3.声明梯度下降优化算法
    optimizer = tf.keras.optimizers.SGD(learning_rate=0.01)

    # 查看初始化模型参数之后的值
    print("训练前模型参数为：权重%f，偏置%f" % (weights.numpy(), bias.numpy()))

    # 4.开始训练
    # 声明循环迭代次数
    num = 1000
    for s in range(num):
        with tf.GradientTape() as tape:
            # 预测值
            y_predict = tf.matmul(X, weights) + bias  # 预测值
            # 损失函数(均方误差)
            loss = tf.reduce_mean(tf.square(y_predict - y_true))
            # 计算梯度
            grads = tape.gradient(loss, variables)
            # 更新参数（最小化某个特定的损失函数）
            optimizer.apply_gradients(grads_and_vars=zip(grads, variables))
            # 每10次打印一次结果
            if s % 10 == 0:
                print("第%f次训练后模型参数为：权重%f，偏置%f，损失为%f" % (s, weights.numpy(), bias.numpy(), loss))

    # 查看初始化模型参数之后的值
    print("训练后模型参数为：权重%f，偏置 %f" % (weights.numpy(), bias.numpy()))

    return None


if __name__ == '__main__':
    # 代码8：自实现线性回归
    linear_refression()
